﻿using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using CRM.Extensions;
using CRM.Models;
using CRM.Services;
using CRM.ViewModels.User;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;

namespace CRM.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UsersController : BaseController
    {
        private readonly MyDbContext _dbContext;
        private readonly UserManager<User> _userManager;
        private readonly SignInManager<User> _signInManager;
        private readonly ILogger _logger;


        public UsersController(MyDbContext dbContext,
            UserManager<User> userManager,
            SignInManager<User> signInManager, ILogger<UsersController> logger)
        {
            _dbContext = dbContext;
            _userManager = userManager;
            _signInManager = signInManager;
            _logger = logger;
        }

        [Route("/reg")] //http://localhost:5000/reg
        public async Task<ResultStruct> RegAccount()
        {
            //EFcore 解决 SQLite 没有datetime 类型的问题 https://www.cnblogs.com/WNpursue/p/14745561.html
            //先创建一个user，不包括密码
            var user = new User
            {
                Avatar = "Avatar",
                Email = "admin@sml2.com",
                UserName = "admin",
                Password = "123456",
                TrueName = "姓名A",
                Mobile = "13666666666",
                Pids = "0",
            };
            try
            {
                //将user和密码绑定入库
                var result = await _userManager.CreateAsync(user, user.Password);
                if (result.Succeeded)
                {
                    return Success("注册完成");
                }
                else
                {
                    var info = result.Errors.First();
                    return Error(info.Description, info.Code);
                }
            }
            catch (DbUpdateException e)
            {
                var m = $"{e.Message}@{e.InnerException?.Message}";
                _logger.LogError("应前端避免异常:{M}", m);
                return Error(m, "Error");
            }
        }



        [AllowAnonymous]
        [Route("/checkLogin")] //http://localhost:5000/checkLogin
        public IActionResult CheckLogin()
        {
            //return Success($"User{(User == null ? "无" : $"Identities:{User.Identities.Count()}  Claims:{User.Claims.Count()} 有")}值",
            //    $"{((User?.Identity.IsAuthenticated).Value ? "已" : "未")}登录");
            return Json(new
            {
                User.Identity.IsAuthenticated,
                User.Identity.AuthenticationType,
                IdentitiesCount = User.Identities.Count(),
                Identities = User.Identities.Select(c => new { c.Name, c.Label, Claims = c.Claims.Select(c => new { c.Type, c.Value }) }),
                ClaimsCount = User.Claims.Count(),
                Claims = User.Claims.Select(c => new { c.Type, c.Value })
            });
        }

        // GET
        [AllowAnonymous]
        [HttpGet(nameof(Login))]
        [HttpGet("/softlogin.php")]
        [HttpGet("/Login")] //http://localhost:5000/Login?UserName=admin&PassWord=123456
        public string LoginGet([FromQuery] Login input, [FromServices]IWebHostEnvironment env, [FromServices] OemService oemService)
        {
            if (Login(input, env, oemService).Result.Tag is string s)
            {
                return s;
            }
            return "error";
        }

        [AllowAnonymous]
        [HttpPost(nameof(Login))]
        [HttpPost("/Login")]
        public async Task<ResultStruct> Login(Login Input, [FromServices]IWebHostEnvironment env, [FromServices] OemService oemService)
        {
            var oem = await oemService.GetCurrentOem();
            if (oem == null)
            {
                _logger.LogInformation("oem[{Domain}不存在]", Request.Host.Host);
                return Error(message: "用户不存在", tag: "9");
            }
            
            string username = Input.UserName.Trim();
            var query = UserService.SuperUsers.Contains(username.ToUpper())
                ? _dbContext.Users
                : _dbContext.Users.Where(m => m.OemId == oem.Id);
            
            var waitUser = await query.Where(m => m.UserName == username)
                .Include(m => m.Company)
                .FirstOrDefaultAsync();
            if (null == waitUser)
            {
                ModelState.AddModelError(string.Empty, "用户不存在！");
                return Error(message: "用户不存在", tag: "9");
            }
            if (!waitUser.Enabled)
            {
                return Error(message: "用户被禁用", tag: "3");
            }
            var isPersistent = false;

            var validity = false;
            // 默认公司永久授权
            if (waitUser.Company.Id == 1)
            {
                validity = true;
            } 
            else if (waitUser.Company.ShowValidity > DateTime.Now.GetTimeStamp())
            {
                var parentCompanyId = waitUser.Company.ParentCompanyId;
                var parentCompany = await _dbContext.Company.FirstAsync(m => m.Id == parentCompanyId);
                
                // 父公司授权未过期
                if (parentCompany.Id == 1 || parentCompany.ShowValidity > DateTime.Now.GetTimeStamp())
                {
                    validity = true;
                }
            }
            
            if (!validity)
                return Error(message: "账号已过期", tag: "3");

            // if (waitUser.Company.Id != 1 && waitUser.Company.ShowValidity < DateTime.Now.GetTimeStamp())
            // {
            //     return Error(message: "账号已过期", tag: "3");
            // }
            // 后面的两个参数，一个是是否应用到浏览器Cookie，一个是登录失败是否锁定账户。
            var result = await _signInManager.PasswordSignInAsync(waitUser, Input.PassWord, isPersistent, false);
            if (result.Succeeded)
            {
                await _userManager.GetClaimsAsync(waitUser); //此处会自动把数据库值赋值给User
                //await _signInManager.SignInWithClaimsAsync(waitUser, isPersistent, _userManager.GetClaimsAsync(waitUser).Result);
                var a = User;
                var token = GenerateJwtToken(waitUser);

                var returnStatus = "7";
                var time = DateTime.Now.GetTimeStamp();
                var user = await _userManager.GetUserAsync(User);
                // csrf_token antiforgery.GetAndStoreTokens(HttpContext).RequestToken
                var redirectUri = $"{Request.Scheme}://{Request.Host}/#{waitUser.UserName}#{waitUser.Id}#csrf_token";
                var r = Success(new { accessToken = token });
                r.Tag = $"{returnStatus}|{time}|{token}|{redirectUri}";
                return r;
            }

            return Error(message: "账户或密码不正确", tag: "1");
        }

        private string GenerateJwtToken(User user)
        {
            // generate token that is valid for 7 days
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.UTF8.GetBytes("123456123456123456");
            var claims = _userManager.GetClaimsAsync(user).Result;
            claims.Add(new Claim("UserId", user.Id.ToString()));
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(claims),
                Expires = DateTime.UtcNow.AddDays(7),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
                    SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            return tokenHandler.WriteToken(token);
        }

        [AllowAnonymous]
        [HttpPost(nameof(Logout))]
        [HttpGet("/Logout")]
        public async Task<ResultStruct> Logout()
        {
            await _signInManager.SignOutAsync();
            return Success("已退出", "成功");
        }

        [Route("[action]")]
        public async Task<ResultStruct> Info()
        {
            var allRoutes = await Menu.GetUiRoutesListAsync(_dbContext.Menus);
            var routes = allRoutes.Where(m => {
                bool Check(Menu o) => o.Module.IsNull() || User.HasPermission(o.Module, o.PermissionFlag);
                m.Children = m.Children.Where(Check).ToList();
                return Check(m);
            });
            var user = await _userManager.GetUserAsync(User);
            return Success(new
            {
                user = new
                {
                    user.Id,
                    Username = user.UserName,
                    Name = user.TrueName,
                    Roles = new List<string>() { "admin" },
                    user.Avatar,
                    user.Type,
                },
                routes
            });
        }
    }
}